#include "logmessage.hpp"
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <cerrno>
#include <stdlib.h>
#include <cstring>
#include <unistd.h>
#include <string>

using namespace std;

class Socket
{
    int _sockfd=-1;
    const static int s_backlog = 10;
public:
    Socket()
    {
        _sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if(_sockfd == -1)
        {
            LogMessage(FATAL, "socket:%d:%s", errno, strerror(errno));
            exit(errno);
        }
        LogMessage(DEBUG, "create socket success!");
    }

    ~Socket()
    {
        if(_sockfd!=-1)
        {
            close(_sockfd);
        }  
    }

    void Bind(uint16_t port)
    {
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(port);
        local.sin_addr.s_addr = INADDR_ANY;

        int ret = bind(_sockfd, (sockaddr*)&local, sizeof(local));
        if(ret == -1)
        {
            LogMessage(FATAL, "bind:%d:%s", errno, strerror(errno));
            exit(errno);
        }
        LogMessage(DEBUG, "bind socket success!");
    }

    void Listen()
    {
        int ret = listen(_sockfd, s_backlog);
        if(ret == -1)
        {
            LogMessage(FATAL, "listen:%d:%s", errno, strerror(errno));
            exit(errno);
        }
        LogMessage(DEBUG, "listen socket success!");
    }

    int Accept(string *ip, uint16_t *port)
    {
        sockaddr_in client;
        socklen_t len = sizeof(client);
        int svcsock = accept(_sockfd, (sockaddr*)&client, &len);
        if(svcsock == -1)
        {
            LogMessage(WARNING, "accept:%d:%s", errno, strerror(errno));
            return -1;
        }
        *port = ntohs(client.sin_port);
        char buffer[64];
        inet_ntop(AF_INET, &client.sin_addr, buffer, sizeof(buffer));
        *ip = buffer;
        return svcsock;
    }

    void Connect(const string& ip, uint16_t port)
    {
        sockaddr_in server;
        memset(&server, 0, sizeof(server));
        server.sin_family = AF_INET;
        server.sin_port = htons(port);
        inet_pton(AF_INET, ip.c_str(), &server.sin_addr);
        int ret = connect(_sockfd, (sockaddr*)&server, sizeof(server));
        if(ret == -1)
        {
            LogMessage(FATAL, "connect:%d:%s", errno, strerror(errno));
            exit(errno);
        }
        LogMessage(DEBUG, "connect server success!");
    }

    int GetSocket()
    {
        return _sockfd;
    }
};